// 实现 atoi，将字符串转为整数。

// 该函数首先根据需要丢弃任意多的空格字符，直到找到第一个非空格字符为止。

// 如果第一个非空字符是正号或负号，选取该符号，并将其与后面尽可能多的连续的数字组合起来，这部分字符即为整数的值。

// 如果第一个非空字符是数字，则直接将其与之后连续的数字字符组合起来，形成整数。

// 字符串可以在形成整数的字符后面包括多余的字符，这些字符可以被忽略，它们对于函数没有影响。

// 当字符串中的第一个非空字符序列不是个有效的整数；或字符串为空；或字符串仅包含空白字符时，则不进行转换。

// 若函数不能执行有效的转换，返回 0。

// 说明：

// 假设我们的环境只能存储 32 位有符号整数，其数值范围是 [−231,  231 − 1]。如果数值超过可表示的范围，则返回  INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。

// 示例 1:

// 输入: "42"
// 输出: 42
// 示例 2:

// 输入: "   -42"
// 输出: -42
// 解释: 第一个非空白字符为 '-', 它是一个负号。
//      我们尽可能将负号与后面所有连续出现的数字组合起来，最后得到 -42 。
// 示例 3:

// 输入: "4193 with words"
// 输出: 4193
// 解释: 转换截止于数字 '3' ，因为它的下一个字符不为数字。
// 示例 4:

// 输入: "words and 987"
// 输出: 0
// 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
//      因此无法执行有效的转换。
// 示例 5:

// 输入: "-91283472332"
// 输出: -2147483648
// 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 
//      因此返回 INT_MIN (−231) 。

#include "../stdc++.h"

class Solution {
public:
    int myAtoi(string str) {
        int n = str.size();
        if (n == 0) return 0;
        int sign = 1, base = 0, i = 0;
        // 跳过前面的空白
        while (i < n && str[i] == ' ') {
            ++i;
        }
        // 符号
        if (str[i] == '+' || str[i] == '-') { 
            sign = (str[i] == '+') ? 1 : -1;
            ++i;
        }
        while (i < n && str[i] >= '0' && str[i] <= '9') {
            if (base > INT32_MAX / 10 || 
                (base == INT32_MAX / 10 && str[i] - '0' > 7)) {
                // INT32_MAX (2147483647) or INT32_MIN (-2147483648) 
                // 32位int的最大值 2147483647 的最后一位，即 7 == INT_MAX % 10
                return (sign == 1) ? INT32_MAX : INT32_MIN;
            }
            base = 10 * base + (str[i] - '0');
            ++i;
        }
        return base * sign;
    }
};

// 有限自动机
class Automation {
public:
    int sign{1};
    long long res{0};
    void get(char c) {
        state = table[state][get_col(c)];
        if (state == "in_number") {
            res = res * 10 + c - '0';
            res = sign == 1 ? min(res, static_cast<long long>(INT_MAX)) : min(res, -static_cast<long long>(INT_MIN));
        } else if (state == "signed") {
            sign = c == '+' ? 1 : -1;
        }
    }
private:
    string state{"start"};
    unordered_map<string, vector<string>> table = {
        {"start", {"start", "signed", "in_number", "end"}},
        {"signed", {"end", "end", "in_number", "end"}},
        {"in_number", {"end", "end", "in_number", "end"}},
        {"end", {"end", "end", "end", "end"}}
    };
    int get_col(char c) {
        if (isspace(c)) {
            return 0;
        }
        if (c == '+' || c == '-') {
            return 1;
        }
        if (isdigit(c)) {
            return 2;
        }
        return 3;
    }
};

class Solution {
public:
    int myAtoi(string str) {
        Automation automation;
        for (char c : str) {
            automation.get(c);
        }
        return automation.sign * automation.res;
    }
};
